####################################################################
#                                                                  #
# 功能： 简单模拟自动取款机                                        #
#        (实现登录、验密、存、取、查余、查明细、改密等)            #
#                                                                  #
# 目的： 学习Pyhon基础知识，如列表、字典、函数，递归、循环等知识   #
#                                                                  #
# 作者：文体彬                                                     #
#                                                                  #
# 日期：20190301                                                   #
#                                                                  #
# 版本：1.0                                                        #
#                                                                  #
####################################################################



import datetime  #导入日期时间模块，为交易明细记录函数addck准备


#定义银行客户列表，一共有3个客户，第个客户有3个属性:姓名(name)，密码(PWD)，存款(ck)，都赋于一定的期初存款，在列表内用字典表示
strlist=({'name':'张三','pwd':'123','ck':10000.00},
         {'name':'李四','pwd':'456','ck':20000.00},
         {'name':'王五','pwd':'789','ck':30000.00})


#定义交易明细列表，3位银行客户每初始化1条期初余额数据，在列表内用字典表示
cklist=[
      {'name':'张三','time':'2019-02-28 00:00:00','outin':0,'all':10000.00,'zy':'期初余额'},
      {'name':'李四','time':'2019-02-28 00:00:00','outin':0,'all':20000.00,'zy':'期初余额'},
      {'name':'王五','time':'2019-02-28 00:00:00','outin':0,'all':30000.00,'zy':'期初余额'}
    ]



#定义查找客户函数
def namefind(strlist,na):

   '''
功能：查找客户并返回客户字典信息

形参：2个
     1、strlist ( list )：要找的列表，在这个列表里面找
     2、na ( string ):要找的目标客户
     
返回（ dict ）：找到 返回该客户的字典信息，否则返回空字典

'''
   for i in range(len(strlist)):
      if strlist[i]['name']==na:
         return strlist[i]
   else:
      return {}


   
#定义查询余额函数
def showstu(cyr):

   '''
功能：直接打印出户名和余额

形参：1个
     1、cyr ( dict )：要查询的客户字典）
     
返回( None )：无返回值，直接打印出户名和余额

'''
   print('-'*20)
   print('|{:<5}|{:<8}|'.format('户名','余额'))
   print("|{}|".format('-'*18))
   print('|{:<5}|{:>10.2f}|'.format(cyr['name'],cyr['ck']))
   print('-'*20)
   
   







       
#定义查询明细函数   
def showck(cklist,doname):

   '''
功能：直接打印出目标客户明细

形参：2个
      1、cklist ( list )：要找的交易明细列表，在这个列表里面找
      2、doname ( string ):要返回明细的目标客户
     
返回( None )：无返回值，直接打印出目标客户明细

'''

   #表头部分
   print('-'*20,'交易明细','-'*27)
   print('|户名：{:<48}|'.format(doname))
   print('-'*58)
   print('|{:2}|{:<18}|{:<6}|{:<10}|{:<7}|'.format('ID','时间','发生额','余额','摘要'))
   print("|{}|".format('-'*56))

   #表身部分，循环输出目标客户的明细   
   j=0
   for i in range(len(cklist)):
      if cklist[i]['name']==doname:   #找到目标客户
               j+=1                   # j累加，用ID方式展现
               print('|{:2}|{:<20}|{:>9.2f}|{:>12.2f}|{:<8}|'.format(j,cklist[i]['time'],cklist[i]['outin'],cklist[i]['all'],cklist[i]['zy']))   #循环输出目标客户的明细
               
   #表尾部分            
   print("|{}|".format('-'*56))
   


#定义交易明细记录函数      
def addck(cklist,doer,cq,flg):

   '''
功能：将当前交易行为记录追加到交易明细列表

形参：4个
      1、cklist ( list )：交易明细列表，将当前交易行为记录追加到这个列表里面去
      2、doer( dict ):当前交易的目标客户字典
      3、cq ( float ):当前的交易金额
      4、flg (int）存取标识,存 = 1,取 = -1
     
返回( None )：无返回值，直接将当前交易行为记录追加到交易明细列表cklist

'''
   #定义一个空字典，将当前交易行为写进入
   d0={}
   d0['name']=doer['name']
   d0['time']=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') #取当前日期时间
   d0['outin']=cq*flg                                               #当前交易金额，存为正，取为负
   d0['all']=doer['ck']
   
   if flg>0:
      d0['zy']='存'
   else:
      d0['zy']='取'
      
   cklist.append(d0)


   
#定义验密函数   
def pwdpass(strmsg,pwd,psumerro=0):

   '''
功能：验密

形参：3个
      1、strmsg ( string )：每次输入密码时的 Input 函数的提示信息
      2、pwd( string ):正确密码
      3、psumerro ( int ):密码错误次数
   
     
返回( int )：返回密码错误次数.

'''
   inpwd=input(strmsg).strip()
   if inpwd==pwd:      #如果密码相等正确，直接返回0
      return 0
   else:
      if psumerro>=2:  #如果密码密码错误次数3次，返回密码错误次数,否则密码错误次数（psumerro）累加后递归调用自身,
              return psumerro
      return pwdpass('密码错误'+str(psumerro+1)+'次！\n请再次输入操作密码： ',pwd,psumerro+1)





######################################### 【 开始了 】 ##########################################################
  

print('='*12,'欢迎使用银行取款机','='*10,'\n')

inname=input('请输入姓名：').strip()
doman=namefind(strlist,inname)#调用查找客户函数，在列表strlist中返回目标客户inname的字典信息赋给doman，每个客户有3个属性:姓名(name)，密码(PWD)，存款(ck)

if not doman:  #如doman是空字典，退出
   print(inname+'： 不是本行客户！！')
   exit()
   

if  pwdpass('请输入操作密码： ',doman['pwd'])>=2: #调用验密函数，看输入的密码是否正确，目标客户的正确密码doman['pwd'])，如果错3次，强行退出！
    print('密码错误,无权进入！！')
    exit()
   

#户名、密码验证正确后 进入取款机操作界面
while True:

    print('='*12,'欢迎使用银行取款机','='*10)
    print('{}{:5}{:>15}'.format(' ','1、取款','2、存款'))
    print('{}{:5}{:>16}'.format(' ','3、查余','4、查明细'))
    print('{}{:5}{:>15}'.format(' ','5、改密','6、退出'))
    print('='*42)
    
    key=input('请输入对应的选择：')
     
    if key=='1':  #  取款                      
         print('='*12,'取款','='*10)
         outno=float(input('请输入取款金额：'))
         doman['ck']=doman['ck']-outno   #目标客户的余额减少
         addck(cklist,doman,outno,-1)    #调用交易明细记录函数  ，将目标客户doman当前交易行为记录追加到交易明细列表cklist中去，outno:发生额，-1：取款
         showstu(doman)                  #调用查询余额函数，直接打印出目标客户doman的户名和余额
         
    elif key=='2':   #  存款
         print('='*12,'存款','='*10)
         inno=float(input('请输入存款金额：'))
         doman['ck']=doman['ck']+inno #目标客户的余额增加
         addck(cklist,doman,inno,1)   #调用交易明细记录函数  ，将目标客户doman的当前交易行为记录追加到交易明细列表cklist中去，outno:发生额，1：存款
         showstu(doman)               #调用查询余额函数，直接打印出目标户名和余额
         
    elif key=='3':   #  查余
         print('='*12,'查余','='*10)
         showstu(doman)                #调用查询余额函数，直接打印出目标客户doman的户名和余额
         
    elif key=='4':   #  查明细
         print('='*12,'查明细','='*10)
         showck(cklist,inname)          #调用查询明细函数，直接打印出目标客户doman的明细，cklist：明细总表，inname：当前客户名称
         
    elif key=='5':   #  改密
         print('='*12,'改密','='*10)
         p1=input('请输入新密码：')
         p2=input('请再次输入新密码：')
         print('='*42)
         if p1==p2:                   #两次输入的新密码相同，则修改目标客户doman的密码，doman['pwd']=p1
                 doman['pwd']=p1
                 if pwdpass('密码修改成功并且即可生效！！\n重新进入主界面前请输入密码：',doman['pwd'])<2: #调用验密函数，看输入的密码是否正确，目标客户的正确密码doman['pwd'])，如果错3次，强行退出！
                    continue                                                                              #密码正确，进入取款机操作界面
                 else:
                    print('密码错误,无权进入！！')
                    exit()
         else:
                 print('两次密码输入不一致，修改密码失败！！')
         
    elif key=='6':   #  退出
         print('='*12,'退出','='*10)
         break
      
    else:             
          print('='*12,'无效输入','='*10)
          
     
    input('按任意键继续！')
